package com.guosen.zebra.framework.starter.sso.utils;

import com.sun.crypto.provider.SunJCE;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

/**
 * 此类从SSO提供的JAR包反编译而来
 **/
public final class PSOCryptography
{
    private static final String CodingType = "UTF8";
    private static final String DigestAlgorithm = "SHA1";
    private static final String CryptAlgorithm = "DESede/CBC/PKCS5Padding";
    private static final String KeyAlgorithm = "DESede";
    public static final byte[] defaultIV = { 1, 2, 3, 4, 5, 6, 7, 8 };

    static {
        Security.addProvider(new SunJCE());
    }

    private PSOCryptography(){}

    public static byte[] Base64Encode(byte[] b) { return java.util.Base64.getEncoder().encode(b); }

    public static String GenerateDigest(String strTobeDigest) {
        byte[] input;

        try {
            input = strTobeDigest.getBytes(CodingType);
        }
        catch (Exception ex) {
            return "create AuthenticatorDigest getBytes error" + ex.getMessage();
        }

        byte[] output = null;
        try {
            MessageDigest DigestGenerator = MessageDigest.getInstance(DigestAlgorithm);
            DigestGenerator.update(input);
            output = DigestGenerator.digest();
        } catch (NoSuchAlgorithmException ex) {
            return "create GenerateDigest Authenticator SHA1 error:" + ex.getMessage();
        }

        return new String(Base64Encode(output));
    }

    public static String Encrypt(String strTobeEnCrypted, String strKey, byte[] byteIV) throws Exception {
        Key k;
        byte[] output;
        byte[] input;

        try {
            input = strTobeEnCrypted.getBytes(CodingType);
        } catch (UnsupportedEncodingException ex) {
            return "inner Encrypt creat input strTobeEnCrypted getBytes error:" + ex.getMessage();
        }

        try {
            k = KeyGenerator(strKey);
        } catch (Exception ex) {
            return "inner Encrypt creat key error::" + ex.getMessage() + "IASKey:" + strKey;
        }
        try {
            IvParameterSpec IVSpec = (byteIV.length == 0) ? IvGenerator(defaultIV) : IvGenerator(byteIV);
            Cipher c = Cipher.getInstance(CryptAlgorithm);
            c.init(1, k, IVSpec);
            output = c.doFinal(input);

        }
        catch (Exception ex) {
            return "inner Encrypt error:" + ex.getMessage();
        }
        return new String(Base64Encode(output), CodingType);
    }

    private static IvParameterSpec IvGenerator(byte[] b) { return new IvParameterSpec(b); }

    private static Key KeyGenerator(String KeyStr) throws Exception {
        byte[] input;

        try {
            input = Hex.decode(KeyStr);
        }
        catch (Exception ex) {
            throw new Exception("create key hex error:" + ex.getMessage() + ":" + KeyStr);
        }

        try {
            DESedeKeySpec KeySpec = new DESedeKeySpec(input);
            SecretKeyFactory KeyFactory = SecretKeyFactory.getInstance(KeyAlgorithm);
            return KeyFactory.generateSecret(KeySpec);
        }
        catch (Exception ex) {
            throw new Exception("create key KeySpec error : " + ex.getMessage() + ":" + KeyAlgorithm + ":" + KeyStr);
        }
    }
}

